package com.sangsang.kafka.processor;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.google.auto.service.AutoService;
import com.sangsang.domain.annotation.CDC;
import com.sangsang.kafka.domain.constants.CDCPackageConstant;
import com.sangsang.kafka.domain.dto.CDCDto;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 自动生成@CDC的mapper 和 consumer
 *
 * @author liutangqi
 * @date 2024/3/11 16:26
 */
@SupportedAnnotationTypes("com.sangsang.domain.annotation.CDC")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@AutoService(Processor.class)
public class CDCConsumerProcessor extends AbstractProcessor {

    private static final Logger log = LoggerFactory.getLogger(CDCConsumerProcessor.class);
    //引入 CustomMapper 的包
    private final static String CUSTOMERMAPPER_IMPORT = "import com.sangsang.ck.basemapper.CustomMapper; ";

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        if (CollectionUtils.isNotEmpty(annotations)) {
            log.warn("***************CDC开始编译**********************");
        }
        for (TypeElement annotation : annotations) {
            //过滤，只获取 TypeElement
            Set<TypeElement> annotatedElements = roundEnv.getElementsAnnotatedWith(annotation)
                    .stream()
                    .filter(f -> f instanceof TypeElement)
                    .map(m -> (TypeElement) m)
                    .collect(Collectors.toSet());
            for (TypeElement element : annotatedElements) {
                //解析实体类信息
                CDCDto cdcDto = this.parseClassMsg(element);

                //生成baseMapper
                buildCDCMapper(cdcDto);

                //生成consumer
                CDC cdc = element.getAnnotation(CDC.class);
                buildCDCConsumer(cdcDto, cdc);
            }
        }
        return true;

    }


    /**
     * 解析标注了注解的类信息
     *
     * @author liutangqi
     * @date 2024/3/12 17:48
     * @Param [typeElement]
     **/
    private CDCDto parseClassMsg(TypeElement typeElement) {
        return CDCDto.builder()
                .referenceEntityName(typeElement.getQualifiedName().toString())
                .entityName(typeElement.getSimpleName().toString())
                .build();
    }

    /**
     * 构建CDC的mapper
     *
     * @author liutangqi
     * @date 2024/3/12 17:49
     * @Param [cdcDto]
     **/
    private void buildCDCMapper(CDCDto cdcDto) {
        String mapperName = getMapperName(cdcDto);
        String packagePath = CDCPackageConstant.MAPPER_PACKAGE;

        PrintWriter out = null;
        try {
            JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(packagePath + "." + mapperName);
            Writer writer = sourceFile.openWriter();
            out = new PrintWriter(writer);
            out.println("package " + packagePath + "; ");
            out.println(CUSTOMERMAPPER_IMPORT);
            out.println("import " + cdcDto.getReferenceEntityName() + "; ");
            out.println("public interface " + mapperName + " extends CustomMapper<" + cdcDto.getEntityName() + "> { }");
        } catch (Exception e) {
            processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Error generating class: " + e.getMessage());
        } finally {
            if (out != null) {
                out.close();
            }
        }
    }

    /**
     * 构建consumer
     *
     * @author liutangqi
     * @date 2024/3/12 18:05
     * @Param [cdcDto, cdc]
     **/
    private void buildCDCConsumer(CDCDto cdcDto, CDC cdc) {

        String consumerName = getConsumerName(cdcDto);
        String packagePath = getConsumerPath(cdcDto);

        PrintWriter out = null;
        try {
            JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(packagePath + "." + consumerName);
            Writer writer = sourceFile.openWriter();
            out = new PrintWriter(writer);
            out.println("package " + packagePath + "; ");
            out.println(" import " + cdcDto.getReferenceEntityName() + "  ; ");
            out.println(" import " + CDCPackageConstant.MAPPER_PACKAGE + "." + getMapperName(cdcDto) + "  ; ");
            out.println(" import com.sangsang.kafka.consumer.AbstractCDCConsumerTemplate; ");
            out.println(" import com.sangsang.kafka.config.KafkaConfiguration; ");
            out.println(" import org.apache.kafka.clients.consumer.ConsumerRecord; ");
            out.println(" import org.springframework.kafka.annotation.KafkaListener; ");
            out.println(" import org.springframework.stereotype.Component; ");
            out.println(" import java.util.List; ");
            out.println("@Component ");
            out.println("public class " + consumerName + " extends AbstractCDCConsumerTemplate<" + cdcDto.getEntityName() + ", " + getMapperName(cdcDto) + "> { ");
            out.println(" @KafkaListener(topics = \"" + cdc.topic() + "\", ");
            out.println(" groupId = \"" + cdc.groupId() + "\", ");
            out.println(" containerFactory = KafkaConfiguration.SINGLE_CONSUME_BATCH_FACTORY) ");
            out.println(" @Override");
            out.println(" protected void consumer(List<ConsumerRecord<String, String>> records) {");
            out.println("   processData(records);");
            out.println(" }");
            out.println("} ");
        } catch (Exception e) {
            processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Error generating class: " + e.getMessage());
        } finally {
            if (out != null) {
                out.close();
            }
        }
    }


    /**
     * 获取生成的mapper的类名
     *
     * @author liutangqi
     * @date 2024/3/13 9:09
     * @Param [dto]
     **/
    private String getMapperName(CDCDto dto) {
        return dto.getEntityName() + "CDCMapper";
    }

    /**
     * 获取生成的consumer的类名
     *
     * @author liutangqi
     * @date 2024/3/13 9:14
     * @Param [dto]
     **/
    public String getConsumerName(CDCDto dto) {
        return dto.getEntityName() + "CDCConsumer";
    }

    /**
     * 获取consumer的包名
     *
     * @author liutangqi
     * @date 2024/3/13 9:17
     * @Param [dto]
     **/
    private String getConsumerPath(CDCDto dto) {
        return CDCPackageConstant.BASE_PACKAGE + ".consumer";
    }
}